<?php

/*
 * Copyright 2008 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#namespace tehframework\events;

#use tehframework\testing\phpunit\TestCase;

require_once 'test/testHelper.php';

class EventHandlerTest extends TestCase
{
	const EVENT_ARGS_INTERFACE = 'EventArgs';
	
	private $listenerCalls;
	
	function testConstructorRegistersSuppliedListeners()
	{
		$this->listenerCalls = 0;
		
		$eventHandler = new EventHandlerImpl(array(
			array($this, 'listenerTest'),
			array($this, 'listenerTest'),
			array($this, 'listenerTest')
		));
		
		$this->assertEquals(3, count($eventHandler));
	}
	
	function testAddListenerIncreasesListenersCountByOne()
	{
		$eventHandler = new EventHandlerImpl();
		
		$eventHandler->addListener(array($this, 'listenerTest'));
		$this->assertEquals(1, count($eventHandler));
		
		$eventHandler->addListener(array($this, 'listenerTest'));
		$this->assertEquals(2, count($eventHandler));
		
		$eventHandler->addListener(array($this, 'listenerTest'));
		$this->assertEquals(3, count($eventHandler));
	}
	
	function testAddListenerAddsTheSpecifiedListener()
	{
		$this->listenerCalls = 0;
		
		$eventHandler = new EventHandlerImpl();
		$eventHandler
			->addListener(array($this, 'listenerTest'))
			->addListener(array($this, 'listenerTest'))
			->addListener(array($this, 'listenerTest'));
		
		$this->assertEquals(3, count($eventHandler));
	}
	
	function testFireEventExecutesEventsInFifoOrder()
	{
		$this->listenerCalls = array();
		
		$eventHandler = new EventHandlerImpl();
		$eventHandler
			->addListener(array($this, 'listenerOrderTest1st'))
			->addListener(array($this, 'listenerOrderTest2nd'))
			->addListener(array($this, 'listenerOrderTest3rd'))
			->fireEvent($this, $this->getMock(self::EVENT_ARGS_INTERFACE));
		
		$this->assertSame(arraY('1st', '2nd', '3rd'), $this->listenerCalls);
	}
	
	function testHasListenerReturnsTrueIfSpecifiedListenerIsAlreadyRegistered()
	{
		$eventHandler = new EventHandlerImpl();
		$eventHandler->addListener($listener = array($this, 'listenerTest'));
		
		$this->assertTrue($eventHandler->hasListener($listener));
	}
	
	function testHasListenerReturnsFalseIfSpecifiedListenerIsNotRegistered()
	{
		$eventHandler = new EventHandlerImpl();
		
		$this->assertFalse(
			$eventHandler->hasListener(array($this, 'listenerTest')));
	}
	
	function testRemoveListenerRemovesTheFirstEncounteredCallbackOfSpecifiedType()
	{
		$listener = array($this, 'listenerTest');
		
		$eventHandler = new EventHandlerImpl();
		$eventHandler
			->addListener($listener)
			->addListener($listener);
		
		$this->assertEquals(2, count($eventHandler));
		
		$eventHandler->removeListener($listener);
		
		$this->assertEquals(1, count($eventHandler));
	}
	
	function testRemoveListenersRemovesAllCallbacksOfSpecifiedType()
	{
		$listener = array($this, 'listenerTest');
		
		$eventHandler = new EventHandlerImpl();
		$eventHandler
			->addListener($listener)
			->addListener($listener);
		
		$this->assertEquals(2, count($eventHandler));
		
		$eventHandler->removeListeners($listener);
		
		$this->assertEquals(0, count($eventHandler));
	}
	
	#region Helper listeners
	
	public function listenerTest($sender, EventArgs $e)
	{
		++$this->listenerCalls;
	}
	
	public function listenerOrderTest1st($sender, EventArgs $e)
	{
		$this->listenerCalls[] = '1st';
	}
	
	public function listenerOrderTest2nd($sender, EventArgs $e)
	{
		$this->listenerCalls[] = '2nd';
	}
	
	public function listenerOrderTest3rd($sender, EventArgs $e)
	{
		$this->listenerCalls[] = '3rd';
	}
	
	#endregion
}